/**
 * 权限工具
 * @author luguoxiang
 * @date 2021-09-07
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
import { useRoute } from 'vue-router';
import {Reactive, reactive, ref, Ref} from 'vue';
import { useAccountStore } from '@/store';

/**
 * 使用权限验证器
 * @param parentPermit 父权限码，非必填，自动读取当前路由权限码
 */
export function useAuth(parentPermit = `${useRoute().meta?.permit}/`) {
  const { permits: regs, roles, user, superAdministrator, tenantId: currTenantId } = useAccountStore();
  /**
   * 是否有某个权限
   * @param permit
   */
  function hasPermit(permit: string | 'create' | 'update' | 'remove' | 'detail' | 'import' | 'export' | 'clear-cache') {
    permit = /^[a-zA-Z0-9].*$/.test(permit) ? `${parentPermit}${permit}` : permit;
    return regs.includes(permit) || isSuperAdministrator();
  }

  /**
   * 是否有某一权限
   * @param permits
   */
  function anyPermit(...permits: string[]) {
    if (isSuperAdministrator()) {
      return true;
    }
    for (let permit of permits) {
      permit = /^[a-zA-Z0-9].*$/.test(permit) ? `${parentPermit}${permit}` : permit;
      if (regs.includes(permit)) {
        return true;
      }
    }
    return false;
  }

  /**
   * 是否是某个角色
   * @param role
   */
  function hasRole(role: string) {
    return roles.includes(role) || isSuperAdministrator();
  }

  /**
   * 是否有某一角色
   * @param roles
   */
  function anyRole(...roles: string[]) {
    if (isSuperAdministrator()) {
      return true;
    }
    for (const role of roles) {
      if (roles.includes(role)) {
        return true;
      }
    }
    return false;
  }

  function hasUserType(userType: any) {
    return user.userType === userType || isSuperAdministrator();
  }

  function anyUserType(...userTypes: any[]) {
    for (const userType of userTypes) {
      if (user.userType === userType) {
        return true;
      }
    }
    return isSuperAdministrator();
  }

  function isSuperAdministrator() {
    return superAdministrator;
  }

  /**
   * 是否有指定租户
   * @param tenantId
   */
  function hasTenant(tenantId: number) {
    return tenantId === currTenantId;
  }

  /**
   * 是否有任意租户
   * @param tenantIds
   */
  function anyTenant(...tenantIds: number[]) {
    return tenantIds.includes(currTenantId);
  }

  return {
    /**
     * 是否有指定权限
     */
    has: hasPermit,
    /**
     * 是否有指定权限
     */
    hasPermit,
    /**
     * 是否有任意一个指定权限
     */
    anyPermit,
    /**
     * 是否有指定角色
     */
    hasRole,
    /**
     * 是否有任意一个指定角色
     */
    anyRole,
    /**
     * 是否是指定用户类型
     */
    hasUserType,
    /**
     * 是否是任意一个指定用户类型
     */
    anyUserType,
    /**
     * 是否是超级管理员
     */
    isSuperAdministrator,
    /**
     * 是否是指定租户
     */
    hasTenant,
    /**
     * 是否是任意一个指定租户
     */
    anyTenant,
  };
}

/**
 * 定义权限
 */
interface Definition {
  /**
   * 新增权限
   */
  create?: string | string[] | 'create';
  /**
   * 修改权限
   */
  update?: string | string[] | 'update';
  /**
   * 删除权限
   */
  remove?: string | string[] | 'remove';
  /**
   * 查看权限
   */
  detail?: string | string[] | 'detail';
  /**
   * 导入权限
   */
  import?: string | string[] | 'import';
  /**
   * 导出权限
   */
  export?: string | string[] | 'export';
  /**
   * 刷新缓存权限
   */
  clearCache?: string | string[] | 'clear-cache';
  /**
   * 其他权限
   */
  [permit: string]: string | string[];
}
/**
 * 使用权限（适用于重复判断权限的场景，提高性能，例如table每一行的操作列按钮权限控制；也适合统一管理权限，权限码变化时不用多处修改）
 * @param definition 权限配置，例：{ create: 'create', update: ['update'], edit: ['create', 'update'] }
 * @param parentPermit 父权限，默认当前菜单权限码
 */
export function usePermit<T extends Definition, R extends { [K in keyof T]: boolean }>(
  definition: T,
  parentPermit = `${useRoute().meta?.permit}/`,
): R {
  const { permits: regs, superAdministrator } = useAccountStore();
  // 初始化
  const map: any = {};
  for (const permit in definition) {
    map[permit] = false;
  }
  const res = reactive<R>(map as R);
  // 是否超级管理员
  if (superAdministrator) {
    for (const permit in definition) {
      res[permit as keyof T] = true;
    }
    return res;
  }
  // 权限判断
  const has = (ps: string[]) => {
    for (let permit of ps) {
      permit = /^[a-zA-Z0-9].*$/.test(permit) ? `${parentPermit}${permit}` : permit;
      if (regs.includes(permit)) {
        return true;
      }
    }
    return false;
  };
  for (const permit in definition) {
    const ps = definition[permit];
    res[permit as keyof T] = has(Array.isArray(ps) ? ps : [ps]);
  }
  return res;
}
